home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
c
/
bchelp10.zip
/
TI738.ASC
< prev
next >
Wrap
Text File
|
1991-11-07
|
38KB
|
991 lines
PRODUCT : Borland C++ NUMBER : 738
VERSION : All
OS : DOS
DATE : November 7, 1991 PAGE : 1/15
TITLE : Memory Corruption
POINTERS:
A pointer is a memory location that holds a memory address as its
contents. When you declare a pointer (e.g. int *foo) the compiler
will allocate the necessary space to hold the appropriate memory
address. If the pointer is declared globally the value of its
address will be 0000 in the case of a near pointer and 0000:0000
in the case of a far pointer. If the pointer is declared inside a
function definition as an auto variable (default), then it is
created on the stack and will have a default address of whatever
value happened to be at that location on the stack when it is
created. In either case these default memory addresses are
invalid. This is referred to as an uninitialized pointer and
should never be dereferenced. To initialize a pointer you must
either dynamically allocate memory using malloc, farmalloc,
calloc, farcalloc, realloc, farrealloc, allocmem or new (C++
only) or you can associate the pointer with a variable who's
memory is allocated by the compiler at compile time (e.g. int
foo[100]). Once the pointer has been initialized it is then safe
to dereference the pointer using the * operator.
int *p; OK Uninitialized pointer
*p = 4; WRONG This puts a value of 4 at whatever
address happened to be stored where *p was
created.
int i; OK Statically declared variable. Static meaning
the memory is allocated by the compiler at
compile time.
p = &i; OK Associating p with a statically declared
variable.
p = (int *) malloc(2); OK Associating p with dynamically
allocated memory. The parameter could also have
been sizeof(int).
Modifying the variable p (e.g. p = 0;) will make the memory
address that p holds equal to 0. When modifying dereferenced p,
denoted by *p, the value stored at the memory address p holds as
its value is modified.
*p = 4; OK p still holds the address that malloc
returned above, but that address in memory
now holds a value of 4.
PRODUCT : Borland C++ NUMBER : 738
VERSION : All
OS : DOS
DATE : November 7, 1991 PAGE : 2/15
TITLE : Memory Corruption
p = 4; OK *p now points to offset 4 from DS. It is
important to note that this type of assignment
should only be made if the address (4 in this
case) is valid. Otherwise memory corruption
will occur. Also note that if a far memory
model (see Memory Models) is used the segment
may not be DS, but will be whatever its initial
value was.
There are 3 types of pointers. They are near, far, and huge.
Near pointers have a size of 2 bytes. They only store the offset
of the address the pointer is referencing. An address consisting
of only an offset has a range of 0 - 64K bytes starting from the
beginning of DGROUP. A near pointer can be incremented and
decremented using arithmetic operators (+, -, ++, and --) through
the entire address range. Any attempt to increment a near pointer
that has a value of 64K (0xffff) will result in a value of 0.
This is referred to as wrapping the pointer. A corresponding
result can be expected when attempting to decrement a pointer
that contains an address of 0, except the result will be 64K
instead of 0. In addition to being incremented and decremented,
near pointers can be compared to one another using relational
operators ( <, >, ==, >= and <= ).
Far pointers have a size of 4 bytes. They store both the segment
and the offset of the address the pointer is referencing. A far
pointer has an address range of 0 - 1M bytes. It is important to
understand that an addressing range of 1M does not remove the
640K barrier from the program. It means that the pointer can
address the upper memory area (641 - 1M) which typically contains
video memory, ROM and anything else that may be loaded high. A
far pointer can be incremented and decremented using arithmetic
operators. When a far pointer is incremented or decremented ONLY
the offset of the pointer is actually incremented or decremented.
The segment is never incremented by the arithmetic operators.
This means that although a far pointer can address up to 1Mb of
memory, it can only be incremented through 64Kb and the offset
will start at zero again without changing the value of the
segment. This is referred to as "wrapping" the pointer (e.g.
0F3E:FFFF + 1 = 0F3E:0000). When a far pointer is decremented
from zero it will wrap the other way and become 64K. Far pointers
are not unique. It is possible to have two far memory addresses
PRODUCT : Borland C++ NUMBER : 738
VERSION : All
OS : DOS
DATE : November 7, 1991 PAGE : 3/15
TITLE : Memory Corruption
that have different segment values and different offset values
that address the same memory location e.g. 0777:2222 has an
absolute address of 07770 + 2222 = 09992 and 0999:0002 has an
absolute address of 09990 + 0002 = 09992. When relational
operators are used on far pointers only the offsets are compared.
For example: if we let a = 0777:2222 and let b = 0999:0002 then a
== b would return false because this is equivalent to 2222 ==
0002 which is in fact false. In other words relational operators
will only work on far pointers if the segment values of the
pointers being compared are the same.
Huge pointers have a size of 4 bytes. They store both the segment
and the offset of the address the pointer is referencing. A huge
pointer has an address range of 0 - 1M bytes. A huge pointer can
be incremented and decremented using arithmetic operators. The
only difference between a far pointer and a huge pointer is that
a huge pointer is normalized by the compiler. A normalized
pointer is one that has as much of the address as possible in the
segment, meaning that the offset is never larger than 15. A huge
pointer is normalized only when pointer arithmetic is performed
on it. It is not normalized when an assignment is made. You can
cause it to be normalized without changing the value by
incrementing and then decrementing it. The offset must be less
than 16 because the segment can represent any value greater than
or equal to 16 (e.g. Absolute address 0x17 in a normalized form
would be 0001:0001. While a far pointer could address the
absolute address 0x17 with 0000:0017, this is not a valid huge
(normalized) pointer because the offset is greater than 0000F.).
Huge pointers can also be incremented and decremented using
arithmetic operators, but since they are normalized they will not
wrap like far pointers. Huge pointers can be reliably used with
relational operators because they are normalized. This works
because normalization of huge pointers insures that every huge
pointer is unique. It is important to understand that huge
pointers are never the default pointer, even in the huge memory
model.
MEMORY MODELS:
The important difference between the memory models are the size
of the data and code pointers, number of data and code segments
and the number and type of heaps available. For our purposes we
will refer to the tiny, small and medium memory models as near
PRODUCT : Borland C++ NUMBER : 738
VERSION : All
OS : DOS
DATE : November 7, 1991